/* eslint-disable @typescript-eslint/no-explicit-any */
import { ActionContext, CommitOptions, DispatchOptions, Store } from 'vuex'
import { State } from '.'
import { AccountActions } from './account/actions'
import { AccountMutations } from './account/mutations'
import { AccountGetters } from './account/getters'
import { GlobalGetters } from './global/getters'
import { GlobalMutations } from './global/mutations'
import { MockTestActions } from './mockTest/actions'
import { MockTestGetters } from './mockTest/getters'
import { MockTestMutations } from './mockTest/mutations'

/**
 * 使 'commit' | 'dispatch' 支持模块命名
 */
export type NameSpaced<T, N extends string> = {
  [K in keyof T & string as `${N}/${K}`]: T[K]
}
/**
 * 所有的 mutation
 */
export type AllMutations = NameSpaced<GlobalMutations, 'global'> &
  NameSpaced<MockTestMutations, 'mockTest'> &
  NameSpaced<AccountMutations, 'account'>
/**
 * 所有的 action
 */
export type AllActions = NameSpaced<MockTestActions, 'mockTest'> &
  NameSpaced<AccountActions, 'account'>
/**
 * 所有的 getter
 */
export type AllGetters = NameSpaced<GlobalGetters, 'global'> &
  NameSpaced<MockTestGetters, 'mockTest'> &
  NameSpaced<AccountGetters, 'account'>
/**
 * 重写全局 'getters' | 'commit' | 'dispatch' 类型
 */
export type AugmentedStore = Omit<
  Store<State>,
  'getters' | 'commit' | 'dispatch'
> & {
  commit: <
    K extends keyof AllMutations,
    P extends Parameters<AllMutations[K]>[1]
  >(
    key: K,
    payload?: P,
    options?: CommitOptions
  ) => ReturnType<AllMutations[K]>
} & {
  dispatch: <
    K extends keyof AllActions,
    P extends Parameters<AllActions[K]>[1]
  >(
    key: K,
    payload?: P,
    options?: DispatchOptions
  ) => ReturnType<AllActions[K]>
} & {
  getters: {
    [K in keyof AllGetters]: ReturnType<AllGetters[K]>
  }
}

/**
 * 重写 ActionContext
 * 需要传入当前模块 state/mutations/actions 类型
 */
export type AugmentActionContext<
  S,
  M = { [key: string]: (...args: any) => any },
  A = { [key: string]: (...args: any) => any }
> = Omit<ActionContext<S, State>, 'commit' | 'dispatch'> & {
  commit: <K extends keyof M>(
    key: K,
    payload?: Parameters<M[K] extends (...args: any) => any ? M[K] : never>[1]
  ) => ReturnType<M[K] extends (...args: any) => any ? M[K] : never>
} & {
  dispatch: <
    K extends keyof A,
    P extends Parameters<A[K] extends (...args: any) => any ? A[K] : never>[1]
  >(
    key: K,
    payload?: P,
    options?: DispatchOptions
  ) => ReturnType<A[K] extends (...args: any) => any ? A[K] : never>
}
